package cn.com.zsw.gblog.modules.user.service.impl;

import cn.com.zsw.gblog.config.cache.RedisCache;
import cn.com.zsw.gblog.constants.SysConstants;
import cn.com.zsw.gblog.modules.user.entity.GbUserEntity;
import cn.com.zsw.gblog.modules.user.entity.ThirdPartUserEntity;
import cn.com.zsw.gblog.modules.user.service.GbUserService;
import cn.com.zsw.gblog.modules.user.service.OauthService;
import cn.com.zsw.gblog.modules.user.service.ThirdPartUserService;
import cn.com.zsw.gblog.modules.user.vo.UserInfoVO;
import cn.com.zsw.gblog.utils.JwtUtils;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import me.zhyd.oauth.enums.AuthUserGender;
import me.zhyd.oauth.model.AuthUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author shiwangzhou
 * @date 2021-06-11
 **/
@Service
public class OauthServiceImpl implements OauthService {

    @Autowired
    GbUserService userService;

    @Autowired
    ThirdPartUserService thirdPartUserService;

    @Qualifier("userDetailsServiceImpl")
    @Autowired
    UserDetailsService userDetailsService;

    @Autowired
    RedisCache redisCache;

    /**
     * 回调方法
     *
     * @param authUser 第三方返回的信息
     * @return cn.com.zsw.gblog.modules.user.vo.UserInfoVO
     * @author shiwangzhou
     * @date 2021-06-11 16:55
     **/
    @Override
    public UserInfoVO oauthCallback(AuthUser authUser) throws Exception {
        //根据openId查询用户,
        ThirdPartUserEntity thirdPartUser = thirdPartUserService.getOne(Wrappers.<ThirdPartUserEntity>lambdaQuery()
                .eq(ThirdPartUserEntity::getOpenId, authUser.getUuid())
                .eq(ThirdPartUserEntity::getPlatform, authUser.getSource()));
        GbUserEntity gbUser;
        if (thirdPartUser == null) {
            //新建用户
            gbUser = userService.createNewUser(authUser.getUsername(), authUser.getAvatar());
            //新建第三方用户关系
            thirdPartUser = new ThirdPartUserEntity();
            thirdPartUser.setAvatar(authUser.getAvatar());
            thirdPartUser.setGender(AuthUserGender.MALE.equals(authUser.getGender()) ? 1 : 0);
            thirdPartUser.setId(IdUtil.createSnowflake(1, 1).nextId());
            thirdPartUser.setNickname(authUser.getNickname());
            thirdPartUser.setUserId(gbUser.getId());
            thirdPartUser.setOpenId(authUser.getUuid());
            thirdPartUser.setUserInfo(JSON.toJSONString(authUser));
            thirdPartUser.setPlatform(authUser.getSource());
            thirdPartUser.setCreateTime(new Date());
            thirdPartUser.setUpdateTime(new Date());
            thirdPartUser.setStatus(1);
            thirdPartUserService.save(thirdPartUser);
        } else {
            gbUser = userService.getById(thirdPartUser.getUserId());
        }
        UserDetails userDetails = userDetailsService.loadUserByUsername(authUser.getUsername());
        //手动执行登录
        UsernamePasswordAuthenticationToken authenticationToken =
                new UsernamePasswordAuthenticationToken(userDetails.getUsername(), userDetails.getPassword(), userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);

        Set<String> collect = userDetails.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toSet());
        Map<String, Object> claims = new HashMap<>(5);
        claims.put(SysConstants.JWT_PERMISSIONS_KEY, JSON.toJSONString(collect));
        claims.put(SysConstants.JWT_USER_NAME, gbUser.getUsername());
        String token = JwtUtils.createToken(gbUser.getId().toString(), claims);
        redisCache.setCacheObject(SysConstants.REDIS_JWT_TOKEN_ID + token, token, 2, TimeUnit.HOURS);
        UserInfoVO userInfoVO = new UserInfoVO();
        userInfoVO.setToken(token);
        userInfoVO.setNickname(authUser.getNickname());
        userInfoVO.setAvatar(authUser.getAvatar());
        userInfoVO.setPermission(collect);
        redisCache.setCacheObject(SysConstants.REDIS_GBLOG_USER_CACHE + gbUser.getId(), userInfoVO, 2, TimeUnit.HOURS);
        return userInfoVO;
    }
}
